#include "loop/EZLoopThreadPool.h"
#include "common/EZLog.h"
#include "loop/EZLoop.h"
#include <assert.h>


namespace EZTcp{


EZLoopThreadPool::EZLoopThreadPool(int thread_num/* = 1*/)
	: thread_num_(thread_num)
	, next_loop_id_(0)
	, status_(kNull)
	, thread_run_num_(0)
	, thread_stop_num_(0)
{
	assert(thread_num_ > 0);
	for(int i = 0; i < thread_num_; ++i){
		EZLoop* loop = new EZLoop;
		loops_.emplace_back(loop);
	}
}


EZLoopThreadPool::~EZLoopThreadPool()
{
	assert(status_.load() == kStopped);
	stop();
}

bool EZLoopThreadPool::start()
{
	assert(status_.load() == kNull);
	if(status_.load() != kNull)
		return status_.load() == kRunning;

	status_.store(kRunning);
	for (auto loop : loops_)
	{
		auto precb = [this](){
			++thread_run_num_;
		};
		loop->post(precb);
		std::thread rth([this,loop](){
			EZLOG_INFO << "loop pool " << loop << "start";
			loop->run();
			EZLOG_INFO << "loop pool " << loop << "stop";
			++thread_stop_num_;
		});
		rth.detach();
		threads_.emplace_back(std::move(rth));
	}
	return true;
}

void EZLoopThreadPool::stop()
{
	if(status_.load() == kStopped)
		return;

	status_.store(kStopped);
	for (auto loop : loops_)
	{
		loop->post([loop](){
			loop->stop();
			delete loop;
		});
	}
	while(thread_stop_num_ != loops_.size())
		std::this_thread::yield();
	loops_.clear();
	threads_.clear();
}

void EZLoopThreadPool::after_fork()
{
    for (auto lp : loops_) {
        lp->after_fork();
    }
}

EZLoop* EZLoopThreadPool::next_loop()
{
	if(status_.load() == kStopped)
		return nullptr;
	return loops_[next_loop_id_++ % thread_num_];
}


}